<?php
ArrowController::importModel("templatesSystem.templates.ArrowTemplatesException" );
ArrowController::importModel("templatesSystem.templates.ArrowTemplateLinker" );
ArrowController::importModel("templatesSystem.schemas.ArrowShemasList");
ArrowController::importModel("access.IArrowControlObject");


/**
 * Arrow template descriptor class
 * 
 * @version 1.0
 * @license  GNU GPL
 * @author Artur Kmera <artur.kmera@arrowplatform.org> 
 */
class ArrowTemplateDescriptor implements ArrayAccess, IArrowSerializable, IArrowControlObject {

	/**
	 * File extension
	 */
	const FILE_EXTENSION = ".tpl";
	
	/**
	 * Handle for Templates structure
	 * 
	 * @var ArrowTemplatesStructure
	 */
	private $templatesStructureHandle;

	/**
	 * Template id
	 *
	 * @var integer
	 */
	private $id;

	/**
	 * Template name
	 *
	 * @var string
	 */
	private $name;

	/**
	 * Template path
	 *
	 * @var string
	 */
	private $path;

	/**
	 * Template description
	 *
	 * @var string
	 */
	private $description;

	/**
	 * Template schema 
	 *
	 * @var ArrowSchemaDescriptor
	 */
	private $schema;
	
	/**
	 * Parent container
	 * 
	 * @var ArrowContainer
	 */
	private $container;
	
	/**
	 * Instance of template page class
	 * 
	 * @var ArrowView
	 */
	private $pageClassInstance = null;

	/**
	 * TemplateDescriptor constructor
	 *
	 * @param ArrowTemplatesStructure $templatesStructureHandle
	 * @param integer $id
	 * @param string $name
	 * @param string $path
	 * @param string $description
	 */
	public function __construct( ArrowTemplatesStructure $templatesStructureHandle, $id, $name, $path, $description) {
		$this->templatesStructureHandle = $templatesStructureHandle;
		$this->id = $id;
		$this->name = $name;
		$this->path = $path;
		$this->description = $description;
		
		$schemaList = ArrowSchemasList::getDefault( $this->templatesStructureHandle->getProject() );
		$this->schema = $schemaList->getParentSchema( $this ); 
		
		//TODO Zbada� co to robilo i ew wyzucic
		/*
		if(!class_exists("ArrowPageClass"))
			require_once $this->getPath()."/PageClass.php";
		*/
	}
	
	public static function getModel() {
		return "templatesSystem.templates.ArrowBeanDescriptor";
	}
	
	public function getUniqueId( ) {
		return array( "model" => self::getModel() , "key" => $this->getId() );
	}
	
	public function getPageClass(){
		$nameAddon = str_replace( array("/", "::"), "_", $this->getMappingPath())."_".$this->getKey().".php";
		$classCacheFile = ARROW_CACHE_PATH."/templates/classes/page_logic_".$nameAddon;
		$className = "ArrowPageClass".$this->id;
		$pageClass = $this->getPath()."/PageClass.php";
		
		if( !file_exists($classCacheFile) || ( !SUPER_CACHE && ( filemtime($classCacheFile) < filemtime($pageClass) || $this->getContainer()->getForceCompile() )) ){
			FB::log("kompiluje page class");
			$schemaClass = $this->getSchema()->getClassFile();
			$schemaClassName = "ArrowSchemaClass".$this->id;
			$content = str_replace(  "ArrowSchemaClass",  $schemaClassName, file_get_contents($schemaClass) );
			
			$content.= str_replace(  array( "ArrowSchemaClass", "ArrowPageClass"  ),  array( $schemaClassName, $className ), file_get_contents($pageClass) );
			file_put_contents( $classCacheFile, $content );
		}
		
		require_once $classCacheFile;
		if( is_null( $this->pageClassInstance ) )
			$this->pageClassInstance = new $className( $this );
		return $this->pageClassInstance;
	}
	

	/**
	 * Saves changed Template data
	 *
	 */
	public function doSave() {
		$this->TemplatesStructureHandle->doTemplateDataChange( $this );
	}
	
	/**
	 * Returns templates structure
	 *
	 * @return ArrowTemplatesStructure
	 */
	public function getTemplatesStructure(){
		return $this->templatesStructureHandle;
	}
	
	/**
	 * Returns template blocks
	 *
	 * @return ArrowTemplatesBlockDescriptor
	 * @todo zaimplementowac
	 */
	public function getBlocks() {
		
	}
	
	/**
	 * Returns template schema
	 *
	 * @return ArrowSchemaDesctiptor
	 */
	public function getSchema() {
		return $this->schema;
	}				

	/**
	 * Returns Template Id
	 * @deprecated Use getKey
	 * @return integer
	 */
	public function getId() {
		return $this->id;
	}

	/**
	 * Returns Template Id
	 * @return integer
	 */
	public function getKey() {
		return $this->id;
	}
	
	/**
	 * Returns Template name
	 *
	 * @return string
	 */
	public function getName() {
		return $this->name;
	}

	/**
	 * Returns Template path
	 *
	 * @return string
	 */
	public function getPath() {
		return $this->path."/".$this->getName();
	}
	
	/**
	 * Returns mapping path /dir/sub:name
	 * 
	 * @return String
	 */
	public function getMappingPath(){
		return str_replace( $this->templatesStructureHandle->sourcesDir, "", $this->path )."::".$this->getName();
	}
	
	/**
	 * Returns Template description
	 *
	 * @return unknown
	 */
	public function getDescription() {
		return $this->description;
	}
	
	/**
	 * Compiles template and return name of compiled template
	 *
	 * @param boolean Force compile parameter
	 * @return string Filename
	 */
	public function getFile( $forceCompile = false ){
		$project = ArrowController::getDefault()->getProject();	
		$filePath =  ARROW_CACHE_PATH."/templates/src/";
		$FileName = "template_".str_replace( array("/", "::"), "_", $this->getMappingPath())."_".$this->getId().".tpl";
		$readable = is_readable($filePath.$FileName);
		$compile = true;
		if( $readable && !SUPER_CACHE ){
			$compile = false;
			$baseTime = filemtime ($filePath.$FileName);
			$path = $this->getPath();
			foreach( scandir($path) as $file){
				if($file != "." && $file != ".." && $file != ".svn"){
					if( $baseTime < filemtime ($path."/".$file)) $compile = true;
				}
			}
			if( $baseTime < filemtime($this->getSchema()->getFile())) $compile = true;
		}
		if(SUPER_CACHE && $readable)
			$compile = false;
		
		if($compile || !$readable || $forceCompile  ){
			FB::log("kompiluje");
			$r = $this->getSource();
			file_put_contents( $filePath.$FileName, $r["source"] );
			$classCacheFile = ARROW_CACHE_PATH."/templates/classes/page_init_".str_replace( array("/", "::"), "_", $this->getMappingPath())."_".$this->getId().".php";
			file_put_contents( $classCacheFile, $r["initCode"] );
			file_put_contents($classCacheFile, php_strip_whitespace($classCacheFile));
		} 
		
		return $FileName;
	}
	
	public function getInitInstuctions(){
		return ARROW_CACHE_PATH."/templates/classes/page_init_".str_replace( array("/", "::"), "_", $this->getMappingPath())."_".$this->getId().".php";
	}
	
	/**
	 * Return template source
	 *
	 * @var boolean $isChild If template is child of another doesn't return php and auth source
	 * @return String
	 */
	public function getSource() {
		
		$parser = ArrowTemplateParser::getDefault();
		$schemaSource = file_get_contents($this->getSchema()->getFile());
		//before parsing setting template for completer
		ArrowTemplateBlock::setTemplate($this);
		
		//Parsing schema by
		$parser->setTargetTags(array( "block:bound", "block:value",  "link:resource", "link:template", "link:bean", "am:ctrl", "link:beanRemoteAccess"));
		$parser->parseString($schemaSource);
		$parsedSchemaSource = $parser->getParsedCode();
		
		//for blocks
		$parser->setTargetTags(array( "block:bound", "block:value",  "link:resource", "link:template", "link:bean", "am:ctrl", "link:beanRemoteAccess"));
		$parser->parseString($parsedSchemaSource);
		$parsedSchemaSource = $parser->getParsedCode();
		
		ArrowNode::$index = 0;
		$parser->clearCache();
		$parser->parseString($parsedSchemaSource);
		$parsedTemplateSource = $parser->getParsedCode();
		
		return array(
			"initCode"=>"<?php\n".$parser->getSetupInstructions().$parser->getPreInitInstructions().$parser->getInitInstructions()."\n?>", 
			"source" => $parsedTemplateSource
		);
	
	}
	
	/**
	 * Return template cointainer
	 *
	 * @return ArrowContainer
	 */
	public function getContainer() {
		$this->container = $this->templatesStructureHandle->getProject()->getContainersList()->getParentContainer($this);
		if( empty( $this->container ) )
			throw new ArrowTemplatesException( "Template {$this->getMappingPath()} doesn't have container", 0 );
		return $this->container;
	}
	
	
	public static function getActions(){
		return array( "show" );
	}
	
	public function checkAccess( IArrowUser $tryier, $action ){
		$accessGroups = $tryier->getAccessGroups();
		foreach( $accessGroups as $accesGroup ){
			if( in_array($this->getKey(), $accesGroup->getTemplates() ) )
				return true;
		}
		return false;
	}
	
	
	
	/**
	 * Sets new Template name
	 *
	 * @param string $name
	 */
	public function setName($name) {
		$this->name = $name;
	}

	/**
	 * Sets new Template Path
	 *
	 * @param unknown_type $path
	 */
	public function setPath($path) {
		$this->path = $path;
	}

	/**
	 * Sets news Template description
	 *
	 * @param string $description
	 */
	public function setDescription($description) {
		$this->description = $description;
	}

	/**
	 * ArrayAcces implementTemplate
	 * 
	 * @param string $key
	 * @return boolean
	 */
	public function offsetExists($key) {
		if (isset ($this->$key))
			return true;
		return false;
	}

	/**
	 * ArrayAcces implementTemplate
	 * 
	 * @param string $key
	 * @return mixed
	 */
	public function offsetGet($key) {
		if ($this->offsetExists($key)) {
			return $this->$key;
		} else {
			throw new ArrowTemplatesException(array( "msg" => "Offset doesn't exist'", "offset" => $key ));
		}
	}
	
	/**
	 * ArrayAcces implementTemplate
	 * 
	 * @param string $key
	 * @param mixed value
	 */
	public function offsetSet($key, $value) {
		throw new ArrowTemplatesException(array( "msg" => "Can't use Array acces to set template value'" ));
	}

	/**
	 * ArrayAcces implementTemplate
	 * 
	 * @param string $key
	 * @return mixed
	 */
	public function offsetUnset($key) {
		throw new ArrowTemplatesException(array( "msg" => "Can't use Array acces to unset template value'" ));
	}
	
	/**
	 * ObjectSerialize implementTemplate
	 * 
	 * @return array Object in array
	 */
	 public function serialize(){
	 	$val = array();
		$val["id"] = $this->id;
		$val["name"] = $this->name;
		$val["path"] = $this->path;
		$val["description"] = $this->description;
	 	return $val;
	 }
	 
	 public function unserialize() {
	 	
		
	 }
	 
	 /**
	  * To string function
	  * 
	  * @return string
	  */
	 public function __toString(){
	 	return "Template id: '{$this->id}', path: {$this->path}, name: {$this->name}";
	 }
}

?>